﻿using System;

namespace PVTLibrary
{
    /// <summary>
    /// Algorithm
    /// </summary>
   public class Brent
   {
        public Func<double, object, double> _fc;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fg"></param>
        public void DefineFuncDelegate(Func<double, object, double>  fg)
        {
            _fc = fg;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <param name="otherargs"></param>
        /// <returns></returns>
        public double func(double x , object otherargs)
        {
            return _fc.Invoke(x, otherargs);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="minval"></param>
        /// <param name="maxval"></param>
        /// <param name="n"></param>
        /// <param name="tol"></param>
        /// <param name="itmax"></param>
        /// <param name="otherargs"></param>
        /// <returns></returns>
        public double BrentOpt(double minval , double maxval, int n , double tol, int itmax, object otherargs)
        {
            double x_inf, x_sup, y_inf, y, delta_x;

            x_inf = minval;
            x_sup = maxval;

            delta_x = (x_sup - x_inf)/n;

            Do
                y = func(x_inf, otherargs)
                x_inf = x_inf + delta_x
                y_inf = func(x_inf, otherargs)
            Loop Until y * y_inf < 0 Or x_inf > x_sup
            x_sup = x_inf - delta_x

            double aaa, bbb, ccc, ddd, eee, min11, min22, faa, fbb, fcc, ppp, qqq, rrr, sss, tol11, xmm;
            int ITMAX2 = itmax;
            int iter2;

            aaa = x_inf;
            bbb = x_sup;
            ccc = x_sup;

            faa = func(x_inf, otherargs);
            fbb = func(x_sup, otherargs);
            fcc = func(x_sup, otherargs);

            iter2 = 0;
            Do
                If (fbb > 0 And fcc > 0) Or (fbb < 0 And fcc < 0) Then
                    ccc = aaa
                    fcc = faa
                    ddd = bbb - aaa
                    eee = ddd
                End If
                If Math.Abs(fcc) < Math.Abs(fbb) Then
                    aaa = bbb
                    bbb = ccc
                    ccc = aaa
                    faa = fbb
                    fbb = fcc
                    fcc = faa
                End If
                tol11 = tol
                xmm = 0.5 * (ccc - bbb)
                If (Math.Abs(xmm) <= tol11) Or (fbb = 0) Then GoTo Final3
                If Math.Abs(fbb) < tol11 Then GoTo Final3
                If (Math.Abs(eee) >= tol11) And (Math.Abs(faa) > Math.Abs(fbb)) Then
                    sss = fbb / faa
                    If aaa = ccc Then
                        ppp = 2 * xmm * sss
                        qqq = 1 - sss
                    Else
                        qqq = faa / fcc
                        rrr = fbb / fcc
                        ppp = sss * (2 * xmm * qqq * (qqq - rrr) - (bbb - aaa) * (rrr - 1))
                        qqq = (qqq - 1) * (rrr - 1) * (sss - 1)
                    End If
                    If ppp > 0 Then qqq = -qqq
                    ppp = Math.Abs(ppp)
                    min11 = 3 * xmm * qqq - Math.Abs(tol11 * qqq)
                    min22 = Math.Abs(eee * qqq)
                    Dim tvar2 As Double
                    If min11 < min22 Then tvar2 = min11
                    If min11 > min22 Then tvar2 = min22
                    If 2 * ppp < tvar2 Then
                        eee = ddd
                        ddd = ppp / qqq
                    Else
                        ddd = xmm
                        eee = ddd
                    End If
                Else
                    ddd = xmm
                    eee = ddd
                End If
                aaa = bbb
                faa = fbb
                If (Math.Abs(ddd) > tol11) Then
                    bbb += ddd
                Else
                    bbb += Math.Sign(xmm) * tol11
                End If
                fbb = func(bbb, otherargs)
                iter2 += 1
            Loop Until iter2 = ITMAX2

            Return bbb

Final3:

            Return bbb

        End Function


 }

}
